Data description
In this tutorial, we aim to obtain differentially expressed genes (DEGs) between two biological conditions in an integrated data. This integrated data set is generated by combining 10 microarray studies on control and TGFb-treated samples (for more information about the data sets, see paper A Transcriptional Program for Detecting TGFβ-Induced EMT in Cancer by Foroutan M et al, 2017.
First, we assess the presence of unwanted variation in the integrated data which combines differents studies and platforms. Second, we show how to use RUV4 to remove unwanted variation and detect DEGs comparing control to TGFb-treated samples. Finally, we assess whether or not running RUV4 method helps, where we include the analysis of unadjusted data.
library(ruv) ## for applying RUV methods
library(limma) ## for vennDiagram()
library(ggplot2) ## for data visualisation
The integrated data introduced above have been split into two data sets: dataset A and dataset B, each containing different studies, platforms and tissues. We will explore and normalise these two data sets separately in order to compare the results obtained by the normalisation method RUV4.
Read in the two integrated datasets.
datasetA<- read.table("expr_10data_datasetA.txt", header = T, sep = "\t")
datasetB<- read.table("expr_10data_datasetB.txt", header = T, sep = "\t")
Look at the each data sets A and B, then make a matrix for each these data sets where the row names are gene IDs.
kable(datasetA[1:4,1:4])
| EntrezID| D_Ctrl_R1| D_TGFb_R1| D_Ctrl_R2|
|--------:|---------:|---------:|---------:|
| 2| 4.182898| 4.234203| 4.271958|
| 9| 5.763352| 6.063185| 5.698005|
| 10| 4.467305| 4.427406| 4.403148|
| 12| 8.597186| 7.814175| 9.019141|
kable(datasetA[1:4,1:4])
| EntrezID| D_Ctrl_R1| D_TGFb_R1| D_Ctrl_R2|
|--------:|---------:|---------:|---------:|
| 2| 4.182898| 4.234203| 4.271958|
| 9| 5.763352| 6.063185| 5.698005|
| 10| 4.467305| 4.427406| 4.403148|
| 12| 8.597186| 7.814175| 9.019141|
mA<-datasetA[,2:dim(datasetA)[2]]
mB<-datasetB[,2:dim(datasetB)[2]]
row.names(mA)<- datasetA[,1]
row.names(mB)<- datasetB[,1]
mA<- as.matrix(mA)
mB<- as.matrix(mB)
Look at the information related to each dataset including the name of the studies, types of platform, treatment, and tissue:
info_datasetA <- read.table("info_10data_datasetA.txt", sep="\t", header=T)
kable(info_datasetA)
|samples |study |treatment |platform |tissue |
|:-----------|:----------|:---------|:-------------|:---------|
|D_Ctrl_R1 |Deshiere |Ctrl |Agilent |Breast |
|D_TGFb_R1 |Deshiere |TGFb |Agilent |Breast |
|D_Ctrl_R2 |Deshiere |Ctrl |Agilent |Breast |
|D_TGFb_R2 |Deshiere |TGFb |Agilent |Breast |
|Hes_Ctrl_R1 |Hesling |Ctrl |HG_U133_Plus2 |Breast |
|Hes_TGFb_R1 |Hesling |TGFb |HG_U133_Plus2 |Breast |
|Hes_Ctrl_R2 |Hesling |Ctrl |HG_U133_Plus2 |Breast |
|Hes_TGFb_R2 |Hesling |TGFb |HG_U133_Plus2 |Breast |
|Hil_Ctrl_R1 |Hills |Ctrl |Illumina |Kidney |
|Hil_Ctrl_R2 |Hills |Ctrl |Illumina |Kidney |
|Hil_Ctrl_R3 |Hills |Ctrl |Illumina |Kidney |
|Hil_TGFb_R1 |Hills |TGFb |Illumina |Kidney |
|Hil_TGFb_R2 |Hills |TGFb |Illumina |Kidney |
|Hil_TGFb_R3 |Hills |TGFb |Illumina |Kidney |
|M_Ctrl_R1 |Maupin |Ctrl |HG_U133_Plus2 |Pancrease |
|M_Ctrl_R2 |Maupin |Ctrl |HG_U133_Plus2 |Pancrease |
|M_Ctrl_R3 |Maupin |Ctrl |HG_U133_Plus2 |Pancrease |
|M_TGFb_R1 |Maupin |TGFb |HG_U133_Plus2 |Pancrease |
|M_TGFb_R2 |Maupin |TGFb |HG_U133_Plus2 |Pancrease |
|M_TGFb_R3 |Maupin |TGFb |HG_U133_Plus2 |Pancrease |
|K_Ctrl_R1 |Keshamouni |Ctrl |HG_U133_Plus2 |Lung |
|K_Ctrl_R2 |Keshamouni |Ctrl |HG_U133_Plus2 |Lung |
|K_Ctrl_R3 |Keshamouni |Ctrl |HG_U133_Plus2 |Lung |
|K_TGFb_R1 |Keshamouni |TGFb |HG_U133_Plus2 |Lung |
|K_TGFb_R2 |Keshamouni |TGFb |HG_U133_Plus2 |Lung |
|K_TGFb_R3 |Keshamouni |TGFb |HG_U133_Plus2 |Lung |
|S_A_Ctrl_R1 |Sun_A549 |Ctrl |HG_U133_Plus2 |Lung |
|S_A_Ctrl_R2 |Sun_A549 |Ctrl |HG_U133_Plus2 |Lung |
|S_A_Ctrl_R3 |Sun_A549 |Ctrl |HG_U133_Plus2 |Lung |
|S_A_TGFb_R1 |Sun_A549 |TGFb |HG_U133_Plus2 |Lung |
|S_A_TGFb_R2 |Sun_A549 |TGFb |HG_U133_Plus2 |Lung |
|S_A_TGFb_R3 |Sun_A549 |TGFb |HG_U133_Plus2 |Lung |
info_datasetB <- read.table("info_10data_datasetB.txt", sep="\t", header=T)
kable(info_datasetB)
|samples |study |treatment |platform |tissue |
|:-------------|:-------|:---------|:-------------|:------|
|S_HCC_Ctrl_R1 |Sun_HCC |Ctrl |HG_U133_Plus2 |Lung |
|S_HCC_Ctrl_R2 |Sun_HCC |Ctrl |HG_U133_Plus2 |Lung |
|S_HCC_Ctrl_R3 |Sun_HCC |Ctrl |HG_U133_Plus2 |Lung |
|S_HCC_TGFb_R1 |Sun_HCC |TGFb |HG_U133_Plus2 |Lung |
|S_HCC_TGFb_R2 |Sun_HCC |TGFb |HG_U133_Plus2 |Lung |
|S_HCC_TGFb_R3 |Sun_HCC |TGFb |HG_U133_Plus2 |Lung |
|S_NCI_Ctrl_R1 |Sun_NCI |Ctrl |HG_U133_Plus2 |Lung |
|S_NCI_Ctrl_R2 |Sun_NCI |Ctrl |HG_U133_Plus2 |Lung |
|S_NCI_Ctrl_R3 |Sun_NCI |Ctrl |HG_U133_Plus2 |Lung |
|S_NCI_TGFb_R1 |Sun_NCI |TGFb |HG_U133_Plus2 |Lung |
|S_NCI_TGFb_R2 |Sun_NCI |TGFb |HG_U133_Plus2 |Lung |
|S_NCI_TGFb_R3 |Sun_NCI |TGFb |HG_U133_Plus2 |Lung |
|T_Ctrl1_R1 |Taube |Ctrl |HT_HG_U133A |Breast |
|T_Ctrl1_R2 |Taube |Ctrl |HT_HG_U133A |Breast |
|T_Ctrl1_R3 |Taube |Ctrl |HT_HG_U133A |Breast |
|T_TGFb_R1 |Taube |TGFb |HT_HG_U133A |Breast |
|T_TGFb_R2 |Taube |TGFb |HT_HG_U133A |Breast |
|T_TGFb_R3 |Taube |TGFb |HT_HG_U133A |Breast |
|T_Ctrl2_R1 |Taube |Ctrl |HT_HG_U133A |Breast |
|T_Ctrl2_R2 |Taube |Ctrl |HT_HG_U133A |Breast |
|T_Ctrl2_R3 |Taube |Ctrl |HT_HG_U133A |Breast |
|W_Ctrl_R1 |Walsh |Ctrl |HG_U133A_2 |Kidney |
|W_Ctrl_R2 |Walsh |Ctrl |HG_U133A_2 |Kidney |
|W_Ctrl_R3 |Walsh |Ctrl |HG_U133A_2 |Kidney |
|W_TGFb_R1 |Walsh |TGFb |HG_U133A_2 |Kidney |
|W_TGFb_R2 |Walsh |TGFb |HG_U133A_2 |Kidney |
|W_TGFb_R3 |Walsh |TGFb |HG_U133A_2 |Kidney |
Assessment of unwanted variation in the data
Here we perform some exploratory analyses on the integrated data sets A and B to assess the presence of unwanted variation in each dataset.
RLE plot
We start by looking at the RLE plots in dataset A, coloured by study, platform and tissue. In a “good” RLE plot, the median of all boxplots (i.e. samples) are around zero, while high deviations from zero show the presence of unwanted variation. For more information about RLE plot see paper RLE Plots: Visualising Unwanted Variation in High Dimensional Data, by Luke C. Gandolfo, Terence P. Speed, 2017.
In the current example, it’s important to note that in some cases, different studies are confounded with different platforms and tissues, and therefore there is no way to identify how much of the unwanted variation come from each of these factors. Such situations must be avoided when designing an experiment, however, it often happens when we perform data integration. For the purpose of this tutorial, we only consider “study” as the source of unwanted variation.
## Transpose the expression matrix so that we have genes in columns and dataset in rows
YA <- t(mA)
## Plot RLE coloured by study
ruv_rle(YA, info_datasetA$study, ylim = c(-5,5))

## Plot RLE coloured by platform
ruv_rle(YA, info_datasetA$platform, ylim = c(-5,5))

## Plot RLE coloured by platform
ruv_rle(YA, info_datasetA$tissue, ylim = c(-5,5))

Similarly, we look at the RLE plots in dataset B coloured by study, platform and tissue:
YB <- t(mB)
## Plot RLE coloured by study
ruv_rle(YB, info_datasetB$study, ylim = c(-5,5))

## Plot RLE coloured by platform
ruv_rle(YB, info_datasetB$platform, ylim = c(-5,5))

## Plot RLE coloured by tissue
ruv_rle(YB, info_datasetB$tissue, ylim = c(-5,5))

PCA plot
In transcriptomics applications, one of the most utilized exploratory plots is the multi-dimensional scaling (MDS) plot or a principal component analysis (PCA) plot. To assess the presence of unwanted variation in each dataset, we use PCA plots to show similarities between samples measured in an unsupervised way. Ideally, samples should be clustered together according to the treatment (i.e. the biological factor of interest). Here, we see that samples are rather clustered by studies (i.e. unwanted variation) in both data sets A and B.
gg_additions <- list(aes(color = info_datasetA$study,
shape = info_datasetA$treatment,
size = 5, alpha = .7),
labs(color = "Study", shape="Treatment"),
scale_size_identity(guide = "none"),
scale_alpha(guide = "none"),
theme(legend.text = element_text(size = 12),
legend.title = element_text(size = 16)),
guides(color = guide_legend(override.aes = list(size = 4)),
shape = guide_legend(override.aes = list(size = 4))))
options(repr.plot.width = 8, repr.plot.height = 6)
ruv_svdplot(YA) + gg_additions

gg_additions <- list(aes(color = info_datasetB$study,
shape = info_datasetB$treatment,
size = 5, alpha = .7),
labs(color = "Study",shape = "Treatment"),
scale_size_identity(guide = "none"),
scale_alpha(guide = "none"),
theme(legend.text = element_text(size = 12),
legend.title = element_text(size = 16)),
guides(color = guide_legend(override.aes = list(size = 4)),
shape = guide_legend(override.aes = list(size = 4))))
options(repr.plot.width=8, repr.plot.height=6)
ruv_svdplot(YB) + gg_additions #

Remove batch effects using RUV-4
There are several RUV methods for removing unwanted variation in order to obtain DEGs, including RUV-2, RUV-4, RUV-inv and RUV-rinv. In general, RUV methods are dependent on negative control genes (genes which are not associated with the biological factor of interest) and replicate samples (if applicable). RUV-2 removes unwanted variation in two steps. RUV-4 was introduced after RUV-2 and has four steps. For RUV-4 we can select different values for dimension of unwanted variation (k), while for RUV-inv and RUV-rinv we don’t need to change k as it is set to be the maximum value. RUV-inv is recommended when we have large number of control genes (~1000), while RUV-rinv is more appropriate with small number of control genes (~60).
Selection of negative control genes is very important. Examples of negative control genes are the spike-in controls or the housekeeping (HK) genes. It is also possible to define empirical negative control genes using an iterative approach. However, it is only recomended if (i) the initial negative control genes are not very good or there are only a few of them; (ii) the beta seems to be very sparse. Therefore, the user needs to generate diagnostic plots to assess the performance of the initial analysis, and only if needed, use an iterative approach to define better control genes. For this tutorial, we use HK genes as negative control genes.
RUV4
RUV4 can be run with different values of k in an attempt to find the optimal value. Note that although there is a function to estimate k, called getK(), this may not give the optimal value for k and is often recomended to be used when there is no other choice but to automate finding k (e.g. in simulations).
We begin with the list of housekeeping (HK) genes as our negative controls.
HKgenes <- read.table("HouseKeeping_genes_IDs.txt", header=T, sep="\t")
hk <- HKgenes$GeneID
ctrl <- colnames(YA) %in% hk
head(ctrl)
[1] FALSE FALSE FALSE FALSE FALSE TRUE
We also define our biological factor of interest (i.e. control versus TGFb treatment)
## Take treatment as the biological factor of interest in data set A
groups_A <- factor(info_datasetA$treatment)
gA <- cbind(as.numeric(groups_A)) ## 1 control, 2: TGFb
## Take treatment as the biological factor of interest in data set B
groups_B <- factor(info_datasetB$treatment)
gB <- cbind(as.numeric(groups_B)) ## 1 control, 2: TGFb
Unadjusted data
RUV4 with k = 0 performs no adjustment when obtaining DEGs, we do this first to see what would be the results if we did not adjust for unwanted variation.
# RUV4 with k = 0 for no adjustment
#----- In dataset A data
fit_unadj_hk_datasetA <- RUV4(YA, X = gA,
ctl = ctrl,
k = 0)
fit_unadj_hk_datasetA.summary <- ruv_summary(YA,
fit_unadj_hk_datasetA,
info_datasetA)
##----- In dataset B data
fit_unadj_hk_datasetB <- RUV4(YB, X = gB,
ctl = ctrl,
k = 0)
fit_unadj_hk_datasetB.summary <- ruv_summary(YB,
fit_unadj_hk_datasetB,
info_datasetB)
Look at the consistency between the results from data sets A and B when no adjustment is perfromed. Here, we look at the correlation between betahats obtained in the two data sets.
##----- Unadjusted data sets
plot(fit_unadj_hk_datasetA$betahat,
fit_unadj_hk_datasetB$betahat,
xlab = "Betahat dataset A",
ylab = "Betahat dataset B",
main = "Unadjusted",
xlim = c(-3,3), cex = 0.3, ylim = c(-4,4))
corVal <- cor.test(fit_unadj_hk_datasetA$betahat, fit_unadj_hk_datasetB$betahat)$estimate
text(-3,3, pos = 4, paste("Correlation: ", round(corVal,2), sep = ""))

RUV4-adjusted data with different values of k
## Take treatment as the biological factor of interest in data set A
groups_A <- factor(info_datasetA$treatment)
gA <- cbind(as.numeric(groups_A)) ## 1 control, 2: TGFb
## Take treatment as the biological factor of interest in data set B
groups_B <- factor(info_datasetB$treatment)
gB <- cbind(as.numeric(groups_B)) ## 1 control, 2: TGFb
## Select different values of k
ks <- c( 1, 2, 5, 6, 7, 8, 10, 11, 12, 15, 18, 20, 22, 23, 24)
## Define empty vector and lists and use them in the for loop to store the results
# beta_corAB_HK <- vector()
fit_ruv4_hk_datasetA_all_k <- list()
fit_ruv4_hk_datasetA_all_k.summary <- list()
fit_ruv4_hk_datasetB_all_k <- list()
fit_ruv4_hk_datasetB_all_k.summary <- list()
for (K in ks){
fit_ruv4_hk_datasetA_all_k[[K]] <- RUV4(YA, X = gA,
ctl = ctrl,
k = K, Z = 1, eta = NULL,
fullW0 = NULL, inputcheck = TRUE)
fit_ruv4_hk_datasetA_all_k.summary[[K]] <- ruv_summary(YA,
fit_ruv4_hk_datasetA_all_k[[K]],
info_datasetA)
fit_ruv4_hk_datasetB_all_k[[K]] <- RUV4(YB, X = gB,
ctl = ctrl,
k = K,Z = 1, eta = NULL,
fullW0 = NULL, inputcheck = TRUE)
fit_ruv4_hk_datasetB_all_k.summary[[K]] <- ruv_summary(YB,
fit_ruv4_hk_datasetB_all_k[[K]],
info_datasetB)
# currentCor <- cor.test(fit_ruv4_hk_datasetA_all_k[[K]]$betahat,
# fit_ruv4_hk_datasetB_all_k[[K]]$betahat)$estimate
# beta_corAB_HK <- c(beta_corAB_HK, currentCor)
plot(fit_ruv4_hk_datasetA_all_k[[K]]$betahat,
fit_ruv4_hk_datasetB_all_k[[K]]$betahat,
xlab = "Betahat dataset A",
ylab = "Betahat dataset B",
main = paste("RUV4_K_", K, sep=""),
xlim = c(-3,3), cex = 0.3, ylim = c(-4,4))
#abline(fit_ruv4_emp_datasetB$betahat,fit_ruv4_emp_datasetA$betahat)
corVal <- cor.test(fit_ruv4_hk_datasetA_all_k[[K]]$betahat,
fit_ruv4_hk_datasetB_all_k[[K]]$betahat)$estimate
text(-3,3, pos=4, paste("Correlation: ", round(corVal,2),sep=""))
}















# names(beta_corAB_HK) <- ks
# data.frame(beta_corAB_HK) ## K = 23 seems a good choice
P-value distributions for unadjusted and RUV4-adjusted data sets
Here we compare the results obtained from unajusted and RUV4- adjusted data using p-value distributions.
## We select K = 23
K = 23
##----- In data A
ruv_hist(fit_unadj_hk_datasetA.summary) + ggtitle("Unadj_A")

ruv_hist(fit_ruv4_hk_datasetA_all_k.summary[[K]]) + ggtitle("RUV4_HK_A")

## ---- In data B
ruv_hist(fit_unadj_hk_datasetB.summary) + ggtitle("Unadj_B")

ruv_hist(fit_ruv4_hk_datasetB_all_k.summary[[K]]) + ggtitle("RUV4_HK_B")

Overlapping DEGs between data sets A and B
Finally, for each of the unadjusted and RUV4-adjusted data sets, we look at the number of overlapping differentially expressed genes (DEGs) between the two data sets A and B.
First, we define DEGs as genes with adjusted p-value < 0.05 and |logFC| > 1 in data sets A and B which are unadjusted, RUV4-adjusted with K = 23, and RUV-4 adjusted with different values of K. In the next step, we look at the overlapping genes.
DEGs in the unadjusted data sets
Venn diagram comparing DEGs obtained from the unadjusted data sets A and B.
##------ Define DEGs in the unadjusted data set A
DEGsUnadj_datasetA <- row.names(fit_unadj_hk_datasetA.summary$C)[fit_unadj_hk_datasetA.summary$C$F.p.BH < 0.05 & abs(fit_unadj_hk_datasetA.summary$C$b_X1) > 1]
##------ Define DEGs in the unadjusted data set B
DEGsUnadj_datasetB <- row.names(fit_unadj_hk_datasetB.summary$C)[fit_unadj_hk_datasetB.summary$C$F.p.BH < 0.05 & abs(fit_unadj_hk_datasetB.summary$C$b_X1) > 1]
##------ Explore how many genes are overlapping between data sets A and B
allDEGs_unadj <- c(DEGsUnadj_datasetA,
DEGsUnadj_datasetB)
## remove duplicated gene symbols:
allDEGs_unadj <- allDEGs_unadj[!duplicated(allDEGs_unadj)]
## Draw a Venn diagram comparing DEGs for RUVinv
Counts_unadj <- matrix(0, nrow = length(allDEGs_unadj), ncol = 2)
row.names(Counts_unadj)<- allDEGs_unadj
colnames(Counts_unadj)<- c("Unadj_A","Unadj_B")
for( i in 1:length(allDEGs_unadj)) {
Counts_unadj[i,1]<- allDEGs_unadj[i] %in% DEGsUnadj_datasetA
Counts_unadj[i,2]<- allDEGs_unadj[i] %in% DEGsUnadj_datasetB
}
col <- c("blue", "violet")
vennDiagram(vennCounts(Counts_unadj),
circle.col = col,
cex = c(1.6, 1.2, 1), lwd=2)

DEGs in the RUV4-adjusted data sets for different values of k
Venn diagram comparing the RUV4-adjusted data sets A and B using different ks.
##---- Define DEGs for different values of k in data set A
DEGsRUV4_datasetA_all_k <- list()
for (K in ks){
DEGsRUV4_datasetA_all_k[[K]] <- row.names(fit_ruv4_hk_datasetA_all_k.summary[[K]]$C)[fit_ruv4_hk_datasetA_all_k.summary[[K]]$C$F.p.BH < 0.05 & abs(fit_ruv4_hk_datasetA_all_k.summary[[K]]$C$b_X1) > 1]
}
##---- Define DEGs for different values of k in data set B
DEGsRUV4_datasetB_all_k <- list()
for (K in ks){
DEGsRUV4_datasetB_all_k[[K]] <- row.names(fit_ruv4_hk_datasetB_all_k.summary[[K]]$C)[fit_ruv4_hk_datasetB_all_k.summary[[K]]$C$F.p.BH < 0.05 & abs(fit_ruv4_hk_datasetB_all_k.summary[[K]]$C$b_X1) > 1]
}
##---- Generate Venn diagrams, looking at the overlapping genes
## between data sets A and B for different values of k
allDEGs_RUV4_all_k <- list()
for (K in ks){
allDEGs_RUV4_all_k[[K]] <- c(DEGsRUV4_datasetA_all_k[[K]],
DEGsRUV4_datasetB_all_k[[K]])
## remove duplicated gene symbols:
allDEGs_RUV4_all_k[[K]] <- allDEGs_RUV4_all_k[[K]][!duplicated(allDEGs_RUV4_all_k[[K]])]
## Draw a Venn diagram comparing DEGs for RUV4
Counts_RUV4<- matrix(0, nrow = length(allDEGs_RUV4_all_k[[K]]), ncol=2)
row.names(Counts_RUV4) <- allDEGs_RUV4_all_k[[K]]
colnames(Counts_RUV4) <- c(paste("RUV4_A_K_", K, sep=""), paste("RUV4_B_K_",K,sep=""))
for( i in 1:length(allDEGs_RUV4_all_k[[K]])) {
Counts_RUV4[i,1]<- allDEGs_RUV4_all_k[[K]][i] %in% DEGsRUV4_datasetA_all_k[[K]]
Counts_RUV4[i,2]<- allDEGs_RUV4_all_k[[K]][i] %in% DEGsRUV4_datasetB_all_k[[K]]
}
col<- c("blue", "violet")
vennDiagram(vennCounts(Counts_RUV4),
circle.col = col,
cex = c(1.6, 1.2, 1), lwd = 2)
}















Overlapping DEGs between unadjusted and RUV4-adjusted data sets
Compare DEGs from the unadjusted and RUV4-adjusted data set A
K = 23
##----- Define DEGs for the RUV4-adjusted data with K = 23 in data set A
DEGsRUV4_datasetA <- row.names(fit_ruv4_hk_datasetA_all_k.summary[[K]]$C)[fit_ruv4_hk_datasetA_all_k.summary[[K]]$C$F.p.BH < 0.05 & abs(fit_ruv4_hk_datasetA_all_k.summary[[K]]$C$b_X1) > 1]
##----- Look at the overalapping genes between unadjusted and RUV-4 adjusted data set A
allDEGs_datasetA <- c(DEGsUnadj_datasetA,
DEGsRUV4_datasetA_all_k[[K]])
## remove duplicated gene symbols:
allDEGs_datasetA <- allDEGs_datasetA[!duplicated(allDEGs_datasetA)]
## Draw a Venn diagram comparing DEGs for dataset A
Counts_datasetA <- matrix(0, nrow= length(allDEGs_datasetA), ncol=2)
row.names(Counts_datasetA)<- allDEGs_datasetA
colnames(Counts_datasetA)<- c("Unadj_A", "Ruv4_A_K_23")
for( i in 1:length(allDEGs_datasetA)) {
Counts_datasetA[i,1]<- allDEGs_datasetA[i] %in% DEGsUnadj_datasetA
Counts_datasetA[i,2]<- allDEGs_datasetA[i] %in% DEGsRUV4_datasetA_all_k[[K]]
}
col<- c("blue","darkgreen")
vennDiagram(vennCounts(Counts_datasetA),
circle.col=col,
cex=c(1.6, 1.2, 1), lwd=2)

Compare DEGs from the unadjusted and RUV4-adjusted data set B
K = 23
##----- Define DEGs for the RUV4-adjusted data with K = 23 in data set B
DEGsRUV4_datasetB <- row.names(fit_ruv4_hk_datasetB_all_k.summary[[K]]$C)[fit_ruv4_hk_datasetB_all_k.summary[[K]]$C$F.p.BH < 0.05 & abs(fit_ruv4_hk_datasetB_all_k.summary[[K]]$C$b_X1) > 1]
##----- Look at the overalapping genes between unadjusted and RUV-4 adjusted data set B
allDEGs_datasetB <- c(DEGsUnadj_datasetB,
DEGsRUV4_datasetB_all_k[[K]])
## remove duplicated gene symbols:
allDEGs_datasetB <- allDEGs_datasetB[!duplicated(allDEGs_datasetB)]
## Draw a Venn diagram comparing DEGs for dataset B
Counts_datasetB <- matrix(0, nrow = length(allDEGs_datasetB), ncol = 2)
row.names(Counts_datasetB) <- allDEGs_datasetB
colnames(Counts_datasetB) <- c("Unadj_B", "Ruv4_B_K_23")
for( i in 1:length(allDEGs_datasetB)) {
Counts_datasetB[i,1]<- allDEGs_datasetB[i] %in% DEGsUnadj_datasetB
Counts_datasetB[i,2]<- allDEGs_datasetB[i] %in% DEGsRUV4_datasetB_all_k[[K]]
}
col <- c("blue", "darkgreen")
vennDiagram(vennCounts(Counts_datasetB),
circle.col = col,
cex = c(1.6, 1.2, 1), lwd = 2)

LS0tCnRpdGxlOiAiSG93IHRvIHJlbW92ZSB1bndhbnRlZCB2YXJpYXRpb24gZnJvbSB0cmFuc2NyaXB0b21pY3MgZGF0YSB1c2luZyBSVVY0IgphdXRob3I6IE1vbWVuZWggKFNlcGlkZWgpIEZvcm91dGFuIGFuZCBNYXJpZSBUcnVzc2FydApvdXRwdXQ6CiAgZ2l0aHViX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICBodG1sX25vdGVib29rOgogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogICAgY29kZV9mb2xkaW5nOiAiaGlkZSIKICAgIGZpZ19jYXB0aW9uOiB5ZXMKLS0tCgoKIyBEYXRhIGRlc2NyaXB0aW9uCkluIHRoaXMgdHV0b3JpYWwsIHdlIGFpbSB0byBvYnRhaW4gZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIChERUdzKSBiZXR3ZWVuIHR3byBiaW9sb2dpY2FsIGNvbmRpdGlvbnMgaW4gYW4gaW50ZWdyYXRlZCBkYXRhLiBUaGlzIGludGVncmF0ZWQgZGF0YSBzZXQgaXMgZ2VuZXJhdGVkIGJ5IGNvbWJpbmluZyAxMCBtaWNyb2FycmF5IHN0dWRpZXMgb24gY29udHJvbCBhbmQgVEdGYi10cmVhdGVkIHNhbXBsZXMgKGZvciBtb3JlIGluZm9ybWF0aW9uIGFib3V0IHRoZSBkYXRhIHNldHMsIHNlZSBwYXBlciBbQSBUcmFuc2NyaXB0aW9uYWwgUHJvZ3JhbSBmb3IgRGV0ZWN0aW5nIFRHRs6yLUluZHVjZWQgRU1UIGluIENhbmNlcl0oaHR0cDovL21jci5hYWNyam91cm5hbHMub3JnL2NvbnRlbnQvMTUvNS82MTkpIGJ5IEZvcm91dGFuIE0gZXQgYWwsIDIwMTcuXCAKCkZpcnN0LCB3ZSBhc3Nlc3MgdGhlIHByZXNlbmNlIG9mIHVud2FudGVkIHZhcmlhdGlvbiBpbiB0aGUgaW50ZWdyYXRlZCBkYXRhIHdoaWNoIGNvbWJpbmVzIGRpZmZlcmVudHMgc3R1ZGllcyBhbmQgcGxhdGZvcm1zLiBTZWNvbmQsIHdlIHNob3cgaG93IHRvIHVzZSBSVVY0IHRvIHJlbW92ZSB1bndhbnRlZCB2YXJpYXRpb24gYW5kIGRldGVjdCBERUdzIGNvbXBhcmluZyBjb250cm9sIHRvIFRHRmItdHJlYXRlZCBzYW1wbGVzLiBGaW5hbGx5LCB3ZSBhc3Nlc3Mgd2hldGhlciBvciBub3QgcnVubmluZyBSVVY0IG1ldGhvZCBoZWxwcywgd2hlcmUgd2UgaW5jbHVkZSB0aGUgYW5hbHlzaXMgb2YgdW5hZGp1c3RlZCBkYXRhLgpgYGB7ciBsb2FkLWxpYnN9CmxpYnJhcnkocnV2KSAgICAgICAgICAgICMjIGZvciBhcHBseWluZyBSVVYgbWV0aG9kCmxpYnJhcnkobGltbWEpICAgICAgICAgICMjIGZvciB2ZW5uRGlhZ3JhbSgpCmxpYnJhcnkoZ2dwbG90MikgICAgICAgICMjIGZvciBkYXRhIHZpc3VhbGlzYXRpb24KbGlicmFyeShrbml0cikgICAgICAgICAgIyMgZm9yIEthYmxlKCkKYGBgCgpUaGUgaW50ZWdyYXRlZCBkYXRhIGludHJvZHVjZWQgYWJvdmUgaGF2ZSBiZWVuIHNwbGl0IGludG8gdHdvIGRhdGEgc2V0czogZGF0YXNldCBBIGFuZCBkYXRhc2V0IEIsIGVhY2ggY29udGFpbmluZyBkaWZmZXJlbnQgc3R1ZGllcywgcGxhdGZvcm1zIGFuZCB0aXNzdWVzLiBXZSB3aWxsIGV4cGxvcmUgYW5kIG5vcm1hbGlzZSB0aGVzZSB0d28gZGF0YSBzZXRzIHNlcGFyYXRlbHkgaW4gb3JkZXIgdG8gY29tcGFyZSB0aGUgcmVzdWx0cyBvYnRhaW5lZCBieSB0aGUgbm9ybWFsaXNhdGlvbiBtZXRob2QgUlVWNC4KClJlYWQgaW4gdGhlIHR3byBpbnRlZ3JhdGVkIGRhdGFzZXRzLgpgYGB7ciBsb2FkLWRhdGF9CmRhdGFzZXRBPC0gcmVhZC50YWJsZSgiZXhwcl8xMGRhdGFfZGF0YXNldEEudHh0IiwgaGVhZGVyID0gVCwgc2VwID0gIlx0IikKZGF0YXNldEI8LSByZWFkLnRhYmxlKCJleHByXzEwZGF0YV9kYXRhc2V0Qi50eHQiLCBoZWFkZXIgPSBULCBzZXAgPSAiXHQiKQpgYGAKCkxvb2sgYXQgdGhlIGVhY2ggZGF0YSBzZXRzIEEgYW5kIEIsIHRoZW4gbWFrZSBhIG1hdHJpeCBmb3IgZWFjaCB0aGVzZSBkYXRhIHNldHMgd2hlcmUgdGhlIHJvdyBuYW1lcyBhcmUgZ2VuZSBJRHMuCmBgYHtyIGV4cGxvcmUtZGF0YX0KCmthYmxlKGRhdGFzZXRBWzE6NCwxOjRdKQprYWJsZShkYXRhc2V0QVsxOjQsMTo0XSkKbUE8LWRhdGFzZXRBWywyOmRpbShkYXRhc2V0QSlbMl1dCm1CPC1kYXRhc2V0QlssMjpkaW0oZGF0YXNldEIpWzJdXQpyb3cubmFtZXMobUEpPC0gZGF0YXNldEFbLDFdCnJvdy5uYW1lcyhtQik8LSBkYXRhc2V0QlssMV0KbUE8LSBhcy5tYXRyaXgobUEpCm1CPC0gYXMubWF0cml4KG1CKQpgYGAKCkxvb2sgYXQgdGhlIGluZm9ybWF0aW9uIHJlbGF0ZWQgdG8gZWFjaCBkYXRhc2V0IGluY2x1ZGluZyB0aGUgbmFtZSBvZiB0aGUgc3R1ZGllcywgdHlwZXMgb2YgcGxhdGZvcm0sIHRyZWF0bWVudCwgYW5kIHRpc3N1ZToKYGBge3IgbG9hZC1pbmZvLXN0dWR5fQppbmZvX2RhdGFzZXRBIDwtIHJlYWQudGFibGUoImluZm9fMTBkYXRhX2RhdGFzZXRBLnR4dCIsIHNlcD0iXHQiLCBoZWFkZXI9VCkKa2FibGUoaW5mb19kYXRhc2V0QSkKaW5mb19kYXRhc2V0QiA8LSByZWFkLnRhYmxlKCJpbmZvXzEwZGF0YV9kYXRhc2V0Qi50eHQiLCBzZXA9Ilx0IiwgaGVhZGVyPVQpCmthYmxlKGluZm9fZGF0YXNldEIpCmBgYAoKIyBBc3Nlc3NtZW50IG9mIHVud2FudGVkIHZhcmlhdGlvbiBpbiB0aGUgZGF0YQpIZXJlIHdlIHBlcmZvcm0gc29tZSBleHBsb3JhdG9yeSBhbmFseXNlcyBvbiB0aGUgaW50ZWdyYXRlZCBkYXRhIHNldHMgQSBhbmQgQiB0byBhc3Nlc3MgdGhlIHByZXNlbmNlIG9mIHVud2FudGVkIHZhcmlhdGlvbiBpbiBlYWNoIGRhdGFzZXQuCgojIyBSTEUgcGxvdApXZSBzdGFydCBieSBsb29raW5nIGF0IHRoZSBSTEUgcGxvdHMgaW4gZGF0YXNldCBBLCBjb2xvdXJlZCBieSBzdHVkeSwgcGxhdGZvcm0gYW5kIHRpc3N1ZS4gSW4gYSAiZ29vZCIgUkxFIHBsb3QsIHRoZSBtZWRpYW4gb2YgYWxsIGJveHBsb3RzIChpLmUuIHNhbXBsZXMpIGFyZSBhcm91bmQgemVybywgd2hpbGUgaGlnaCBkZXZpYXRpb25zIGZyb20gemVybyBzaG93IHRoZSBwcmVzZW5jZSBvZiB1bndhbnRlZCB2YXJpYXRpb24uIEZvciBtb3JlIGluZm9ybWF0aW9uIGFib3V0IFJMRSBwbG90IHNlZSAgcGFwZXIgW1JMRSBQbG90czogVmlzdWFsaXNpbmcgVW53YW50ZWQgVmFyaWF0aW9uIGluIEhpZ2ggRGltZW5zaW9uYWwgRGF0YV0oaHR0cHM6Ly9hcnhpdi5vcmcvYWJzLzE3MDQuMDM1OTApLCBieSBMdWtlIEMuIEdhbmRvbGZvLCBUZXJlbmNlIFAuIFNwZWVkLCAyMDE3LlwKSW4gdGhlIGN1cnJlbnQgZXhhbXBsZSwgaXQncyBpbXBvcnRhbnQgdG8gbm90ZSB0aGF0IGluIHNvbWUgY2FzZXMsIGRpZmZlcmVudCBzdHVkaWVzIGFyZSBjb25mb3VuZGVkIHdpdGggZGlmZmVyZW50IHBsYXRmb3JtcyBhbmQgdGlzc3VlcywgYW5kIHRoZXJlZm9yZSB0aGVyZSBpcyBubyB3YXkgdG8gaWRlbnRpZnkgaG93IG11Y2ggb2YgdGhlIHVud2FudGVkIHZhcmlhdGlvbiBjb21lIGZyb20gZWFjaCBvZiB0aGVzZSBmYWN0b3JzLiBTdWNoIHNpdHVhdGlvbnMgbXVzdCBiZSBhdm9pZGVkIHdoZW4gZGVzaWduaW5nIGFuIGV4cGVyaW1lbnQsIGhvd2V2ZXIsIGl0IG9mdGVuIGhhcHBlbnMgd2hlbiB3ZSBwZXJmb3JtIGRhdGEgaW50ZWdyYXRpb24uIEZvciB0aGUgcHVycG9zZSBvZiB0aGlzIHR1dG9yaWFsLCB3ZSBvbmx5IGNvbnNpZGVyICJzdHVkeSIgYXMgdGhlIHNvdXJjZSBvZiB1bndhbnRlZCB2YXJpYXRpb24uXAoKYGBge3IgcmxlcGxvdHMtZGF0YXNldEF9CiMjIFRyYW5zcG9zZSB0aGUgZXhwcmVzc2lvbiBtYXRyaXggc28gdGhhdCB3ZSBoYXZlIGdlbmVzIGluIGNvbHVtbnMgYW5kIGRhdGFzZXQgaW4gcm93cwpZQSA8LSB0KG1BKQojIyBQbG90IFJMRSBjb2xvdXJlZCBieSBzdHVkeQpydXZfcmxlKFlBLCBpbmZvX2RhdGFzZXRBJHN0dWR5LCB5bGltID0gYygtNSw1KSkKIyMgUGxvdCBSTEUgY29sb3VyZWQgYnkgcGxhdGZvcm0KcnV2X3JsZShZQSwgaW5mb19kYXRhc2V0QSRwbGF0Zm9ybSwgeWxpbSA9IGMoLTUsNSkpCiMjIFBsb3QgUkxFIGNvbG91cmVkIGJ5IHBsYXRmb3JtCnJ1dl9ybGUoWUEsIGluZm9fZGF0YXNldEEkdGlzc3VlLCB5bGltID0gYygtNSw1KSkKYGBgCgpTaW1pbGFybHksIHdlIGxvb2sgYXQgdGhlIFJMRSBwbG90cyBpbiBkYXRhc2V0IEIgY29sb3VyZWQgYnkgc3R1ZHksIHBsYXRmb3JtIGFuZCB0aXNzdWU6CmBgYHtyIHJsZXBsb3RzLWRhdGFzZXRCfQpZQiA8LSB0KG1CKQojIyBQbG90IFJMRSBjb2xvdXJlZCBieSBzdHVkeQpydXZfcmxlKFlCLCBpbmZvX2RhdGFzZXRCJHN0dWR5LCB5bGltID0gYygtNSw1KSkKIyMgUGxvdCBSTEUgY29sb3VyZWQgYnkgcGxhdGZvcm0KcnV2X3JsZShZQiwgaW5mb19kYXRhc2V0QiRwbGF0Zm9ybSwgeWxpbSA9IGMoLTUsNSkpCiMjIFBsb3QgUkxFIGNvbG91cmVkIGJ5IHRpc3N1ZQpydXZfcmxlKFlCLCBpbmZvX2RhdGFzZXRCJHRpc3N1ZSwgeWxpbSA9IGMoLTUsNSkpCmBgYAoKIyMgUENBIHBsb3QKSW4gdHJhbnNjcmlwdG9taWNzIGFwcGxpY2F0aW9ucywgb25lIG9mIHRoZSBtb3N0IHV0aWxpemVkIGV4cGxvcmF0b3J5IHBsb3RzIGlzIHRoZSBtdWx0aS1kaW1lbnNpb25hbCBzY2FsaW5nIChNRFMpIHBsb3Qgb3IgYSBwcmluY2lwYWwgY29tcG9uZW50IGFuYWx5c2lzIChQQ0EpIHBsb3QuIFRvIGFzc2VzcyB0aGUgcHJlc2VuY2Ugb2YgdW53YW50ZWQgdmFyaWF0aW9uIGluIGVhY2ggZGF0YXNldCwgd2UgdXNlIFBDQSBwbG90cyB0byBzaG93IHNpbWlsYXJpdGllcyBiZXR3ZWVuIHNhbXBsZXMgbWVhc3VyZWQgaW4gYW4gdW5zdXBlcnZpc2VkIHdheS4gSWRlYWxseSwgc2FtcGxlcyBzaG91bGQgYmUgY2x1c3RlcmVkIHRvZ2V0aGVyIGFjY29yZGluZyB0byB0aGUgdHJlYXRtZW50IChpLmUuIHRoZSBiaW9sb2dpY2FsIGZhY3RvciBvZiBpbnRlcmVzdCkuIEhlcmUsIHdlIHNlZSB0aGF0IHNhbXBsZXMgYXJlIHJhdGhlciBjbHVzdGVyZWQgYnkgc3R1ZGllcyAoaS5lLiB1bndhbnRlZCB2YXJpYXRpb24pIGluIGJvdGggZGF0YSBzZXRzIEEgYW5kIEIuXAoKYGBge3IgbWRzLXBsb3QtZGF0YXNldEF9CmdnX2FkZGl0aW9ucyA8LSBsaXN0KGFlcyhjb2xvciA9IGluZm9fZGF0YXNldEEkc3R1ZHksIAogICAgICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSBpbmZvX2RhdGFzZXRBJHRyZWF0bWVudCwgCiAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gNSwgYWxwaGEgPSAuNyksCiAgICAgICAgICAgICAgICAgICAgIGxhYnMoY29sb3IgPSAiU3R1ZHkiLCBzaGFwZSA9ICJUcmVhdG1lbnQiKSwKICAgICAgICAgICAgICAgICAgICAgc2NhbGVfc2l6ZV9pZGVudGl0eShndWlkZSA9ICJub25lIiksCiAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2FscGhhKGd1aWRlID0gIm5vbmUiKSwKICAgICAgICAgICAgICAgICAgICAgdGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNikpLAogICAgICAgICAgICAgICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNCkpKSkKb3B0aW9ucyhyZXByLnBsb3Qud2lkdGggPSA4LCByZXByLnBsb3QuaGVpZ2h0ID0gNikKcnV2X3N2ZHBsb3QoWUEpICsgZ2dfYWRkaXRpb25zIApgYGAKCmBgYHtyIG1kcy1wbG90LWRhdGFzZXRCfQpnZ19hZGRpdGlvbnMgPC0gbGlzdChhZXMoY29sb3IgPSBpbmZvX2RhdGFzZXRCJHN0dWR5LAogICAgICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSBpbmZvX2RhdGFzZXRCJHRyZWF0bWVudCwKICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSA1LCBhbHBoYSA9IC43KSwKICAgICAgICAgICAgICAgICAgICAgbGFicyhjb2xvciA9ICJTdHVkeSIsc2hhcGUgPSAiVHJlYXRtZW50IiksCiAgICAgICAgICAgICAgICAgICAgIHNjYWxlX3NpemVfaWRlbnRpdHkoZ3VpZGUgPSAibm9uZSIpLAogICAgICAgICAgICAgICAgICAgICBzY2FsZV9hbHBoYShndWlkZSA9ICJub25lIiksCiAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpKSwKICAgICAgICAgICAgICAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDQpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDQpKSkpCm9wdGlvbnMocmVwci5wbG90LndpZHRoPTgsIHJlcHIucGxvdC5oZWlnaHQ9NikKcnV2X3N2ZHBsb3QoWUIpICsgZ2dfYWRkaXRpb25zICMKYGBgCgoKIyBSZW1vdmUgYmF0Y2ggZWZmZWN0cyB1c2luZyBSVVYtNApUaGVyZSBhcmUgc2V2ZXJhbCBSVVYgbWV0aG9kcyBmb3IgcmVtb3ZpbmcgdW53YW50ZWQgdmFyaWF0aW9uIGluIG9yZGVyIHRvIG9idGFpbiBERUdzLCBpbmNsdWRpbmcgUlVWLTIsIFJVVi00LCBSVVYtaW52IGFuZCBSVVYtcmludi4gSW4gZ2VuZXJhbCwgUlVWIG1ldGhvZHMgYXJlIGRlcGVuZGVudCBvbiBuZWdhdGl2ZSBjb250cm9sIGdlbmVzIChnZW5lcyB3aGljaCBhcmUgbm90IGFzc29jaWF0ZWQgd2l0aCB0aGUgYmlvbG9naWNhbCBmYWN0b3Igb2YgaW50ZXJlc3QpIGFuZCByZXBsaWNhdGUgc2FtcGxlcyAoaWYgYXBwbGljYWJsZSkuIFJVVi0yIHJlbW92ZXMgdW53YW50ZWQgdmFyaWF0aW9uIGluIHR3byBzdGVwcy4gUlVWLTQgd2FzIGludHJvZHVjZWQgYWZ0ZXIgUlVWLTIgYW5kIGhhcyBmb3VyIHN0ZXBzLiBGb3IgUlVWLTQgd2UgY2FuIHNlbGVjdCBkaWZmZXJlbnQgdmFsdWVzIGZvciBkaW1lbnNpb24gb2YgdW53YW50ZWQgdmFyaWF0aW9uIChrKSwgd2hpbGUgZm9yIFJVVi1pbnYgYW5kIFJVVi1yaW52IHdlIGRvbid0IG5lZWQgdG8gY2hhbmdlIGsgYXMgaXQgaXMgc2V0IHRvIGJlIHRoZSBtYXhpbXVtIHZhbHVlLiBSVVYtaW52IGlzIHJlY29tbWVuZGVkIHdoZW4gd2UgaGF2ZSBsYXJnZSBudW1iZXIgb2YgY29udHJvbCBnZW5lcyAofjEwMDApLCB3aGlsZSBSVVYtcmludiBpcyBtb3JlIGFwcHJvcHJpYXRlIHdpdGggc21hbGwgbnVtYmVyIG9mIGNvbnRyb2wgZ2VuZXMgKH42MCkuXAoKU2VsZWN0aW9uIG9mIG5lZ2F0aXZlIGNvbnRyb2wgZ2VuZXMgaXMgdmVyeSBpbXBvcnRhbnQuIEV4YW1wbGVzIG9mIG5lZ2F0aXZlIGNvbnRyb2wgZ2VuZXMgYXJlIHRoZSBzcGlrZS1pbiBjb250cm9scyBvciB0aGUgaG91c2VrZWVwaW5nIChISykgZ2VuZXMuIEl0IGlzIGFsc28gcG9zc2libGUgdG8gZGVmaW5lIGVtcGlyaWNhbCBuZWdhdGl2ZSBjb250cm9sIGdlbmVzIHVzaW5nIGFuIGl0ZXJhdGl2ZSBhcHByb2FjaC4gSG93ZXZlciwgaXQgaXMgb25seSByZWNvbWVuZGVkIGlmIChpKSB0aGUgaW5pdGlhbCBuZWdhdGl2ZSBjb250cm9sIGdlbmVzIGFyZSBub3QgdmVyeSBnb29kIG9yIHRoZXJlIGFyZSBvbmx5IGEgZmV3IG9mIHRoZW07IChpaSkgdGhlIGJldGEgc2VlbXMgdG8gYmUgdmVyeSBzcGFyc2UuIFRoZXJlZm9yZSwgdGhlIHVzZXIgbmVlZHMgdG8gZ2VuZXJhdGUgZGlhZ25vc3RpYyBwbG90cyB0byBhc3Nlc3MgdGhlIHBlcmZvcm1hbmNlIG9mIHRoZSBpbml0aWFsIGFuYWx5c2lzLCBhbmQgb25seSBpZiBuZWVkZWQsIHVzZSBhbiBpdGVyYXRpdmUgYXBwcm9hY2ggdG8gZGVmaW5lIGJldHRlciBjb250cm9sIGdlbmVzLiBGb3IgdGhpcyB0dXRvcmlhbCwgd2UgdXNlIEhLIGdlbmVzIGFzIG5lZ2F0aXZlIGNvbnRyb2wgZ2VuZXMuCgoKIyMgUlVWNApSVVY0IGNhbiBiZSBydW4gd2l0aCBkaWZmZXJlbnQgdmFsdWVzIG9mIGsgaW4gYW4gYXR0ZW1wdCB0byBmaW5kIHRoZSBvcHRpbWFsIHZhbHVlLiBOb3RlIHRoYXQgYWx0aG91Z2ggdGhlcmUgaXMgYSBmdW5jdGlvbiB0byBlc3RpbWF0ZSBrLCBjYWxsZWQgZ2V0SygpLCB0aGlzIG1heSBub3QgZ2l2ZSB0aGUgb3B0aW1hbCB2YWx1ZSBmb3IgayBhbmQgaXMgb2Z0ZW4gcmVjb21lbmRlZCB0byBiZSB1c2VkIHdoZW4gdGhlcmUgaXMgbm8gb3RoZXIgY2hvaWNlIGJ1dCB0byBhdXRvbWF0ZSBmaW5kaW5nIGsgKGUuZy4gaW4gc2ltdWxhdGlvbnMpLiAKCldlIGJlZ2luIHdpdGggdGhlIGxpc3Qgb2YgaG91c2VrZWVwaW5nIChISykgZ2VuZXMgYXMgb3VyIG5lZ2F0aXZlIGNvbnRyb2xzLgpgYGB7cn0KSEtnZW5lcyA8LSByZWFkLnRhYmxlKCJIb3VzZUtlZXBpbmdfZ2VuZXNfSURzLnR4dCIsIGhlYWRlcj1ULCBzZXA9Ilx0IikKaGsgPC0gSEtnZW5lcyRHZW5lSUQKY3RybCA8LSBjb2xuYW1lcyhZQSkgJWluJSBoawpoZWFkKGN0cmwpCmBgYAoKV2UgYWxzbyBkZWZpbmUgb3VyIGJpb2xvZ2ljYWwgZmFjdG9yIG9mIGludGVyZXN0IChpLmUuIGNvbnRyb2wgdmVyc3VzIFRHRmIgdHJlYXRtZW50KQpgYGB7cn0KIyMgVGFrZSB0cmVhdG1lbnQgYXMgdGhlIGJpb2xvZ2ljYWwgZmFjdG9yIG9mIGludGVyZXN0IGluIGRhdGEgc2V0IEEKZ3JvdXBzX0EgPC0gZmFjdG9yKGluZm9fZGF0YXNldEEkdHJlYXRtZW50KSAKZ0EgPC0gY2JpbmQoYXMubnVtZXJpYyhncm91cHNfQSkpICAgIyMgMSBjb250cm9sLCAyOiBUR0ZiCgojIyBUYWtlIHRyZWF0bWVudCBhcyB0aGUgYmlvbG9naWNhbCBmYWN0b3Igb2YgaW50ZXJlc3QgaW4gZGF0YSBzZXQgQgpncm91cHNfQiA8LSBmYWN0b3IoaW5mb19kYXRhc2V0QiR0cmVhdG1lbnQpIApnQiA8LSBjYmluZChhcy5udW1lcmljKGdyb3Vwc19CKSkgICAjIyAxIGNvbnRyb2wsIDI6IFRHRmIKCmBgYAoKIyMjIFVuYWRqdXN0ZWQgZGF0YQpSVVY0IHdpdGggayA9IDAgcGVyZm9ybXMgbm8gYWRqdXN0bWVudCB3aGVuIG9idGFpbmluZyBERUdzLCB3ZSBkbyB0aGlzIGZpcnN0IHRvIHNlZSB3aGF0IHdvdWxkIGJlIHRoZSByZXN1bHRzIGlmIHdlIGRpZCBub3QgYWRqdXN0IGZvciB1bndhbnRlZCB2YXJpYXRpb24uCmBgYHtyIERFLXVuYWRqdXN0ZWQtQS1CLXVzaW5nLUhLfQojIFJVVjQgd2l0aCBrID0gMCBmb3Igbm8gYWRqdXN0bWVudAojLS0tLS0gSW4gZGF0YXNldCBBIGRhdGEKZml0X3VuYWRqX2hrX2RhdGFzZXRBIDwtIFJVVjQoWUEsIFggPSBnQSwKICAgICAgICAgICAgICAgICAgICAgICAgICBjdGwgPSBjdHJsLAogICAgICAgICAgICAgICAgICAgICAgICAgIGsgPSAwKQpmaXRfdW5hZGpfaGtfZGF0YXNldEEuc3VtbWFyeSA8LSBydXZfc3VtbWFyeShZQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpdF91bmFkal9oa19kYXRhc2V0QSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZm9fZGF0YXNldEEpCgojIy0tLS0tIEluIGRhdGFzZXQgQiBkYXRhCmZpdF91bmFkal9oa19kYXRhc2V0QiA8LSBSVVY0KFlCLCBYID0gZ0IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgY3RsID0gY3RybCwKICAgICAgICAgICAgICAgICAgICAgICAgICBrID0gMCkKZml0X3VuYWRqX2hrX2RhdGFzZXRCLnN1bW1hcnkgPC0gcnV2X3N1bW1hcnkoWUIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZml0X3VuYWRqX2hrX2RhdGFzZXRCLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZm9fZGF0YXNldEIpCgpgYGAKCkxvb2sgYXQgdGhlIGNvbnNpc3RlbmN5IGJldHdlZW4gdGhlIHJlc3VsdHMgZnJvbSBkYXRhIHNldHMgQSBhbmQgQiB3aGVuIG5vIGFkanVzdG1lbnQgaXMgcGVyZnJvbWVkLiBIZXJlLCB3ZSBsb29rIGF0IHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIGJldGFoYXRzIG9idGFpbmVkIGluIHRoZSB0d28gZGF0YSBzZXRzLgoKYGBge3J9CiMjLS0tLS0gVW5hZGp1c3RlZCBkYXRhIHNldHMKcGxvdChmaXRfdW5hZGpfaGtfZGF0YXNldEEkYmV0YWhhdCwgCiAgICAgZml0X3VuYWRqX2hrX2RhdGFzZXRCJGJldGFoYXQsCiAgICAgeGxhYiA9ICJCZXRhaGF0IGRhdGFzZXQgQSIsCiAgICAgeWxhYiA9ICJCZXRhaGF0IGRhdGFzZXQgQiIsCiAgICAgbWFpbiA9ICJVbmFkanVzdGVkIiwKICAgICB4bGltID0gYygtMywzKSwgY2V4ID0gMC4zLCB5bGltID0gYygtNCw0KSkKY29yVmFsIDwtIGNvci50ZXN0KGZpdF91bmFkal9oa19kYXRhc2V0QSRiZXRhaGF0LCAKICAgICAgICAgICAgICAgICAgIGZpdF91bmFkal9oa19kYXRhc2V0QiRiZXRhaGF0KSRlc3RpbWF0ZQp0ZXh0KC0zLDMsIHBvcyA9IDQsIHBhc3RlKCJDb3JyZWxhdGlvbjogIiwgcm91bmQoY29yVmFsLDIpLCBzZXAgPSAiIikpCgpgYGAKCgojIyMgUlVWNC1hZGp1c3RlZCBkYXRhIHdpdGggZGlmZmVyZW50IHZhbHVlcyBvZiBrCmBgYCB7ciBydXY0LUhLLWRpZmZlcmVudEtzfQojIyBTZWxlY3QgZGlmZmVyZW50IHZhbHVlcyBvZiBrCmtzIDwtIGMoIDEsIDIsIDUsIDYsIDcsIDgsIDEwLCAxMSwgMTIsIDE1LCAxOCwgMjAsIDIyLCAyMywgMjQpCgojIyBEZWZpbmUgZW1wdHkgbGlzdHMgYW5kIHVzZSB0aGVtIGluIHRoZSBmb3IgbG9vcCB0byBzdG9yZSB0aGUgcmVzdWx0cwpmaXRfcnV2NF9oa19kYXRhc2V0QV9hbGxfayA8LSBsaXN0KCkKZml0X3J1djRfaGtfZGF0YXNldEFfYWxsX2suc3VtbWFyeSA8LSBsaXN0KCkKZml0X3J1djRfaGtfZGF0YXNldEJfYWxsX2sgPC0gbGlzdCgpCmZpdF9ydXY0X2hrX2RhdGFzZXRCX2FsbF9rLnN1bW1hcnkgPC0gbGlzdCgpCgpmb3IgKEsgaW4ga3MpewogIGZpdF9ydXY0X2hrX2RhdGFzZXRBX2FsbF9rW1tLXV0gPC0gUlVWNChZQSwgWCA9IGdBLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN0bCA9IGN0cmwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgayA9IEssIFogPSAxLCBldGEgPSBOVUxMLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bGxXMCA9IE5VTEwsIGlucHV0Y2hlY2sgPSBUUlVFKQogIAogIGZpdF9ydXY0X2hrX2RhdGFzZXRBX2FsbF9rLnN1bW1hcnlbW0tdXSA8LSBydXZfc3VtbWFyeShZQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpdF9ydXY0X2hrX2RhdGFzZXRBX2FsbF9rW1tLXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmZvX2RhdGFzZXRBKQogIAogIGZpdF9ydXY0X2hrX2RhdGFzZXRCX2FsbF9rW1tLXV0gPC0gUlVWNChZQiwgWCA9IGdCLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN0bCA9IGN0cmwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgayA9IEssWiA9IDEsIGV0YSA9IE5VTEwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVsbFcwID0gTlVMTCwgaW5wdXRjaGVjayA9IFRSVUUpCiAgCiAgZml0X3J1djRfaGtfZGF0YXNldEJfYWxsX2suc3VtbWFyeVtbS11dIDwtIHJ1dl9zdW1tYXJ5KFlCLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZml0X3J1djRfaGtfZGF0YXNldEJfYWxsX2tbW0tdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZm9fZGF0YXNldEIpCiAgCiAgcGxvdChmaXRfcnV2NF9oa19kYXRhc2V0QV9hbGxfa1tbS11dJGJldGFoYXQsCiAgICAgZml0X3J1djRfaGtfZGF0YXNldEJfYWxsX2tbW0tdXSRiZXRhaGF0LAogICAgIHhsYWIgPSAiQmV0YWhhdCBkYXRhc2V0IEEiLAogICAgIHlsYWIgPSAiQmV0YWhhdCBkYXRhc2V0IEIiLAogICAgIG1haW4gPSBwYXN0ZSgiUlVWNF9LXyIsIEssIHNlcD0iIiksCiAgICAgeGxpbSA9IGMoLTMsMyksIGNleCA9IDAuMywgeWxpbSA9IGMoLTQsNCkpCiAgI2FibGluZShmaXRfcnV2NF9lbXBfZGF0YXNldEIkYmV0YWhhdCxmaXRfcnV2NF9lbXBfZGF0YXNldEEkYmV0YWhhdCkKICBjb3JWYWwgPC0gY29yLnRlc3QoZml0X3J1djRfaGtfZGF0YXNldEFfYWxsX2tbW0tdXSRiZXRhaGF0LAogICAgICAgICAgICAgICAgICAgICBmaXRfcnV2NF9oa19kYXRhc2V0Ql9hbGxfa1tbS11dJGJldGFoYXQpJGVzdGltYXRlCiAgdGV4dCgtMywzLCBwb3M9NCwgcGFzdGUoIkNvcnJlbGF0aW9uOiAiLCByb3VuZChjb3JWYWwsMiksc2VwPSIiKSkKICAKfQpgYGAKCiMjIFAtdmFsdWUgZGlzdHJpYnV0aW9ucyBmb3IgdW5hZGp1c3RlZCBhbmQgUlVWNC1hZGp1c3RlZCBkYXRhIHNldHMKSGVyZSB3ZSBjb21wYXJlIHRoZSByZXN1bHRzIG9idGFpbmVkIGZyb20gdW5hanVzdGVkIGFuZCBSVVY0LSBhZGp1c3RlZCBkYXRhIHVzaW5nIHAtdmFsdWUgZGlzdHJpYnV0aW9ucy4KCmBgYHtyfQojIyBXZSBzZWxlY3QgSyA9IDIzIApLID0gMjMgCiMjLS0tLS0gSW4gZGF0YSBBCnJ1dl9oaXN0KGZpdF91bmFkal9oa19kYXRhc2V0QS5zdW1tYXJ5KSArIGdndGl0bGUoIlVuYWRqX0EiKQpydXZfaGlzdChmaXRfcnV2NF9oa19kYXRhc2V0QV9hbGxfay5zdW1tYXJ5W1tLXV0pICsgZ2d0aXRsZSgiUlVWNF9IS19BIikKCiMjIC0tLS0gSW4gZGF0YSBCCnJ1dl9oaXN0KGZpdF91bmFkal9oa19kYXRhc2V0Qi5zdW1tYXJ5KSArIGdndGl0bGUoIlVuYWRqX0IiKQpydXZfaGlzdChmaXRfcnV2NF9oa19kYXRhc2V0Ql9hbGxfay5zdW1tYXJ5W1tLXV0pICsgZ2d0aXRsZSgiUlVWNF9IS19CIikKYGBgCgojIyBPdmVybGFwcGluZyBERUdzIGJldHdlZW4gZGF0YSBzZXRzIEEgYW5kIEIgCkZpbmFsbHksIGZvciBlYWNoIG9mIHRoZSB1bmFkanVzdGVkIGFuZCBSVVY0LWFkanVzdGVkIGRhdGEgc2V0cywgd2UgbG9vayBhdCB0aGUgbnVtYmVyIG9mIG92ZXJsYXBwaW5nIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyAoREVHcykgYmV0d2VlbiB0aGUgdHdvIGRhdGEgc2V0cyBBIGFuZCBCLlwKCkZpcnN0LCB3ZSBkZWZpbmUgREVHcyBhcyBnZW5lcyB3aXRoIGFkanVzdGVkIHAtdmFsdWUgPCAwLjA1IGFuZCB8bG9nRkN8ID4gMSBpbiBkYXRhIHNldHMgQSBhbmQgQiB3aGljaCBhcmUgdW5hZGp1c3RlZCwgUlVWNC1hZGp1c3RlZCB3aXRoIEsgPSAyMywgYW5kIFJVVi00IGFkanVzdGVkIHdpdGggZGlmZmVyZW50IHZhbHVlcyBvZiBLLiBJbiB0aGUgbmV4dCBzdGVwLCB3ZSBsb29rIGF0IHRoZSBvdmVybGFwcGluZyBnZW5lcy4KCiMjIyBERUdzIGluIHRoZSB1bmFkanVzdGVkIGRhdGEgc2V0cwpWZW5uIGRpYWdyYW0gY29tcGFyaW5nIERFR3Mgb2J0YWluZWQgZnJvbSB0aGUgdW5hZGp1c3RlZCBkYXRhIHNldHMgQSBhbmQgQi4KYGBge3IgVmVubi1ERUdzLXVuYWRqfQojIy0tLS0tLSBEZWZpbmUgREVHcyBpbiB0aGUgdW5hZGp1c3RlZCBkYXRhIHNldCBBCkRFR3NVbmFkal9kYXRhc2V0QSA8LSByb3cubmFtZXMoZml0X3VuYWRqX2hrX2RhdGFzZXRBLnN1bW1hcnkkQylbZml0X3VuYWRqX2hrX2RhdGFzZXRBLnN1bW1hcnkkQyRGLnAuQkggPCAwLjA1ICYgYWJzKGZpdF91bmFkal9oa19kYXRhc2V0QS5zdW1tYXJ5JEMkYl9YMSkgPiAxXQoKIyMtLS0tLS0gRGVmaW5lIERFR3MgaW4gdGhlIHVuYWRqdXN0ZWQgZGF0YSBzZXQgQgpERUdzVW5hZGpfZGF0YXNldEIgPC0gcm93Lm5hbWVzKGZpdF91bmFkal9oa19kYXRhc2V0Qi5zdW1tYXJ5JEMpW2ZpdF91bmFkal9oa19kYXRhc2V0Qi5zdW1tYXJ5JEMkRi5wLkJIIDwgMC4wNSAmIGFicyhmaXRfdW5hZGpfaGtfZGF0YXNldEIuc3VtbWFyeSRDJGJfWDEpID4gMV0KCiMjLS0tLS0tIEV4cGxvcmUgaG93IG1hbnkgZ2VuZXMgYXJlIG92ZXJsYXBwaW5nIGJldHdlZW4gZGF0YSBzZXRzIEEgYW5kIEIKYWxsREVHc191bmFkaiA8LSBjKERFR3NVbmFkal9kYXRhc2V0QSwgCiAgICAgICAgICAgICAgICAgICAgREVHc1VuYWRqX2RhdGFzZXRCKQoKIyMgcmVtb3ZlIGR1cGxpY2F0ZWQgZ2VuZSBzeW1ib2xzOgphbGxERUdzX3VuYWRqIDwtIGFsbERFR3NfdW5hZGpbIWR1cGxpY2F0ZWQoYWxsREVHc191bmFkaildICAKCiMjIERyYXcgYSBWZW5uIGRpYWdyYW0gY29tcGFyaW5nIERFR3MgZm9yIFJVVmludgpDb3VudHNfdW5hZGogPC0gbWF0cml4KDAsIG5yb3cgPSBsZW5ndGgoYWxsREVHc191bmFkaiksIG5jb2wgPSAyKQpyb3cubmFtZXMoQ291bnRzX3VuYWRqKTwtIGFsbERFR3NfdW5hZGoKY29sbmFtZXMoQ291bnRzX3VuYWRqKTwtIGMoIlVuYWRqX0EiLCJVbmFkal9CIikKCmZvciggaSBpbiAxOmxlbmd0aChhbGxERUdzX3VuYWRqKSkgewogIENvdW50c191bmFkaltpLDFdPC0gYWxsREVHc191bmFkaltpXSAlaW4lIERFR3NVbmFkal9kYXRhc2V0QQogIENvdW50c191bmFkaltpLDJdPC0gYWxsREVHc191bmFkaltpXSAlaW4lIERFR3NVbmFkal9kYXRhc2V0Qgp9Cgpjb2wgPC0gYygiYmx1ZSIsICJ2aW9sZXQiKQp2ZW5uRGlhZ3JhbSh2ZW5uQ291bnRzKENvdW50c191bmFkaiksIAogICAgICAgICAgICBjaXJjbGUuY29sID0gY29sLCAKICAgICAgICAgICAgY2V4ID0gYygxLjYsIDEuMiwgMSksIGx3ZD0yKQoKYGBgCgoKIyMjIERFR3MgaW4gdGhlIFJVVjQtYWRqdXN0ZWQgZGF0YSBzZXRzIGZvciBkaWZmZXJlbnQgdmFsdWVzIG9mIGsKVmVubiBkaWFncmFtIGNvbXBhcmluZyB0aGUgUlVWNC1hZGp1c3RlZCBkYXRhIHNldHMgQSBhbmQgQiB1c2luZyBkaWZmZXJlbnQga3MuCmBgYHtyIFZlbm4tREVHcy1SVVY0fQoKIyMtLS0tIERlZmluZSBERUdzIGZvciBkaWZmZXJlbnQgdmFsdWVzIG9mIGsgaW4gZGF0YSBzZXQgQQpERUdzUlVWNF9kYXRhc2V0QV9hbGxfayA8LSBsaXN0KCkKZm9yIChLIGluIGtzKXsKICBERUdzUlVWNF9kYXRhc2V0QV9hbGxfa1tbS11dIDwtIHJvdy5uYW1lcyhmaXRfcnV2NF9oa19kYXRhc2V0QV9hbGxfay5zdW1tYXJ5W1tLXV0kQylbZml0X3J1djRfaGtfZGF0YXNldEFfYWxsX2suc3VtbWFyeVtbS11dJEMkRi5wLkJIIDwgMC4wNSAmIGFicyhmaXRfcnV2NF9oa19kYXRhc2V0QV9hbGxfay5zdW1tYXJ5W1tLXV0kQyRiX1gxKSA+IDFdICAKfQoKIyMtLS0tIERlZmluZSBERUdzIGZvciBkaWZmZXJlbnQgdmFsdWVzIG9mIGsgaW4gZGF0YSBzZXQgQgpERUdzUlVWNF9kYXRhc2V0Ql9hbGxfayA8LSBsaXN0KCkKZm9yIChLIGluIGtzKXsKICBERUdzUlVWNF9kYXRhc2V0Ql9hbGxfa1tbS11dIDwtIHJvdy5uYW1lcyhmaXRfcnV2NF9oa19kYXRhc2V0Ql9hbGxfay5zdW1tYXJ5W1tLXV0kQylbZml0X3J1djRfaGtfZGF0YXNldEJfYWxsX2suc3VtbWFyeVtbS11dJEMkRi5wLkJIIDwgMC4wNSAmIGFicyhmaXRfcnV2NF9oa19kYXRhc2V0Ql9hbGxfay5zdW1tYXJ5W1tLXV0kQyRiX1gxKSA+IDFdICAKfQoKIyMtLS0tIEdlbmVyYXRlIFZlbm4gZGlhZ3JhbXMsIGxvb2tpbmcgYXQgdGhlIG92ZXJsYXBwaW5nIGdlbmVzIAojIyAgICAgYmV0d2VlbiBkYXRhIHNldHMgQSBhbmQgQiBmb3IgZGlmZmVyZW50IHZhbHVlcyBvZiBrCgphbGxERUdzX1JVVjRfYWxsX2sgPC0gbGlzdCgpCgpmb3IgKEsgaW4ga3MpewogIGFsbERFR3NfUlVWNF9hbGxfa1tbS11dIDwtIGMoREVHc1JVVjRfZGF0YXNldEFfYWxsX2tbW0tdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERFR3NSVVY0X2RhdGFzZXRCX2FsbF9rW1tLXV0pCiAgIyMgcmVtb3ZlIGR1cGxpY2F0ZWQgZ2VuZSBzeW1ib2xzOgogIGFsbERFR3NfUlVWNF9hbGxfa1tbS11dIDwtIGFsbERFR3NfUlVWNF9hbGxfa1tbS11dWyFkdXBsaWNhdGVkKGFsbERFR3NfUlVWNF9hbGxfa1tbS11dKV0gIAogICMjIERyYXcgYSBWZW5uIGRpYWdyYW0gY29tcGFyaW5nIERFR3MgZm9yIFJVVjQKICBDb3VudHNfUlVWNDwtIG1hdHJpeCgwLCBucm93ID0gbGVuZ3RoKGFsbERFR3NfUlVWNF9hbGxfa1tbS11dKSwgbmNvbD0yKQogIHJvdy5uYW1lcyhDb3VudHNfUlVWNCkgPC0gYWxsREVHc19SVVY0X2FsbF9rW1tLXV0KICBjb2xuYW1lcyhDb3VudHNfUlVWNCkgPC0gYyhwYXN0ZSgiUlVWNF9BX0tfIiwgSywgc2VwPSIiKSwgcGFzdGUoIlJVVjRfQl9LXyIsSyxzZXA9IiIpKQoKICBmb3IoIGkgaW4gMTpsZW5ndGgoYWxsREVHc19SVVY0X2FsbF9rW1tLXV0pKSB7CiAgICBDb3VudHNfUlVWNFtpLDFdPC0gYWxsREVHc19SVVY0X2FsbF9rW1tLXV1baV0gJWluJSBERUdzUlVWNF9kYXRhc2V0QV9hbGxfa1tbS11dCiAgICBDb3VudHNfUlVWNFtpLDJdPC0gYWxsREVHc19SVVY0X2FsbF9rW1tLXV1baV0gJWluJSBERUdzUlVWNF9kYXRhc2V0Ql9hbGxfa1tbS11dCiAgfQoKICBjb2w8LSBjKCJibHVlIiwgInZpb2xldCIpCiAgdmVubkRpYWdyYW0odmVubkNvdW50cyhDb3VudHNfUlVWNCksIAogICAgICAgICAgICBjaXJjbGUuY29sID0gY29sLCAKICAgICAgICAgICAgY2V4ID0gYygxLjYsIDEuMiwgMSksIGx3ZCA9IDIpCn0KCmBgYAoKIyMgT3ZlcmxhcHBpbmcgREVHcyBiZXR3ZWVuIHVuYWRqdXN0ZWQgYW5kIFJVVjQtYWRqdXN0ZWQgZGF0YSBzZXRzCiMjIyBDb21wYXJlIERFR3MgZnJvbSB0aGUgdW5hZGp1c3RlZCBhbmQgUlVWNC1hZGp1c3RlZCBkYXRhIHNldCBBCmBgYHtyIFZlbm4tREVHcy1kYXRhc2V0QX0KSyA9IDIzCiMjLS0tLS0gRGVmaW5lIERFR3MgZm9yIHRoZSBSVVY0LWFkanVzdGVkIGRhdGEgd2l0aCBLID0gMjMgaW4gZGF0YSBzZXQgQQpERUdzUlVWNF9kYXRhc2V0QSA8LSByb3cubmFtZXMoZml0X3J1djRfaGtfZGF0YXNldEFfYWxsX2suc3VtbWFyeVtbS11dJEMpW2ZpdF9ydXY0X2hrX2RhdGFzZXRBX2FsbF9rLnN1bW1hcnlbW0tdXSRDJEYucC5CSCA8IDAuMDUgJiBhYnMoZml0X3J1djRfaGtfZGF0YXNldEFfYWxsX2suc3VtbWFyeVtbS11dJEMkYl9YMSkgPiAxXSAgCgojIy0tLS0tIExvb2sgYXQgdGhlIG92ZXJhbGFwcGluZyBnZW5lcyBiZXR3ZWVuIHVuYWRqdXN0ZWQgYW5kIFJVVi00IGFkanVzdGVkIGRhdGEgc2V0IEEKYWxsREVHc19kYXRhc2V0QSA8LSBjKERFR3NVbmFkal9kYXRhc2V0QSwgIAogICAgICAgICAgICAgICAgICAgICAgREVHc1JVVjRfZGF0YXNldEFfYWxsX2tbW0tdXSkKCiMjIHJlbW92ZSBkdXBsaWNhdGVkIGdlbmUgc3ltYm9sczoKYWxsREVHc19kYXRhc2V0QSA8LSBhbGxERUdzX2RhdGFzZXRBWyFkdXBsaWNhdGVkKGFsbERFR3NfZGF0YXNldEEpXSAgCgojIyBEcmF3IGEgVmVubiBkaWFncmFtIGNvbXBhcmluZyBERUdzIGZvciBkYXRhc2V0IEEKQ291bnRzX2RhdGFzZXRBIDwtIG1hdHJpeCgwLCBucm93PSBsZW5ndGgoYWxsREVHc19kYXRhc2V0QSksIG5jb2w9MikKcm93Lm5hbWVzKENvdW50c19kYXRhc2V0QSk8LSBhbGxERUdzX2RhdGFzZXRBCmNvbG5hbWVzKENvdW50c19kYXRhc2V0QSk8LSBjKCJVbmFkal9BIiwgIlJ1djRfQV9LXzIzIikKCmZvciggaSBpbiAxOmxlbmd0aChhbGxERUdzX2RhdGFzZXRBKSkgewogIENvdW50c19kYXRhc2V0QVtpLDFdPC0gYWxsREVHc19kYXRhc2V0QVtpXSAlaW4lIERFR3NVbmFkal9kYXRhc2V0QQogIENvdW50c19kYXRhc2V0QVtpLDJdPC0gYWxsREVHc19kYXRhc2V0QVtpXSAlaW4lIERFR3NSVVY0X2RhdGFzZXRBX2FsbF9rW1tLXV0KfQoKY29sPC0gYygiYmx1ZSIsImRhcmtncmVlbiIpCnZlbm5EaWFncmFtKHZlbm5Db3VudHMoQ291bnRzX2RhdGFzZXRBKSwgCiAgICAgICAgICAgIGNpcmNsZS5jb2w9Y29sLCAKICAgICAgICAgICAgY2V4PWMoMS42LCAxLjIsIDEpLCBsd2Q9MikKCmBgYAoKIyMjIENvbXBhcmUgREVHcyBmcm9tIHRoZSB1bmFkanVzdGVkIGFuZCBSVVY0LWFkanVzdGVkIGRhdGEgc2V0IEIgCmBgYHtyIFZlbm4tREVHcy1kYXRhc2V0Qn0KSyA9IDIzCiMjLS0tLS0gRGVmaW5lIERFR3MgZm9yIHRoZSBSVVY0LWFkanVzdGVkIGRhdGEgd2l0aCBLID0gMjMgaW4gZGF0YSBzZXQgQgpERUdzUlVWNF9kYXRhc2V0QiA8LSByb3cubmFtZXMoZml0X3J1djRfaGtfZGF0YXNldEJfYWxsX2suc3VtbWFyeVtbS11dJEMpW2ZpdF9ydXY0X2hrX2RhdGFzZXRCX2FsbF9rLnN1bW1hcnlbW0tdXSRDJEYucC5CSCA8IDAuMDUgJiBhYnMoZml0X3J1djRfaGtfZGF0YXNldEJfYWxsX2suc3VtbWFyeVtbS11dJEMkYl9YMSkgPiAxXSAgCgojIy0tLS0tIExvb2sgYXQgdGhlIG92ZXJhbGFwcGluZyBnZW5lcyBiZXR3ZWVuIHVuYWRqdXN0ZWQgYW5kIFJVVi00IGFkanVzdGVkIGRhdGEgc2V0IEIKYWxsREVHc19kYXRhc2V0QiA8LSBjKERFR3NVbmFkal9kYXRhc2V0QiwKICAgICAgICAgICAgICAgICAgICAgIERFR3NSVVY0X2RhdGFzZXRCX2FsbF9rW1tLXV0pCgojIyByZW1vdmUgZHVwbGljYXRlZCBnZW5lIHN5bWJvbHM6CmFsbERFR3NfZGF0YXNldEIgPC0gYWxsREVHc19kYXRhc2V0QlshZHVwbGljYXRlZChhbGxERUdzX2RhdGFzZXRCKV0gCgojIyBEcmF3IGEgVmVubiBkaWFncmFtIGNvbXBhcmluZyBERUdzIGZvciBkYXRhc2V0IEIKQ291bnRzX2RhdGFzZXRCIDwtIG1hdHJpeCgwLCBucm93ID0gbGVuZ3RoKGFsbERFR3NfZGF0YXNldEIpLCBuY29sID0gMikKcm93Lm5hbWVzKENvdW50c19kYXRhc2V0QikgPC0gYWxsREVHc19kYXRhc2V0Qgpjb2xuYW1lcyhDb3VudHNfZGF0YXNldEIpIDwtIGMoIlVuYWRqX0IiLCAiUnV2NF9CX0tfMjMiKQoKZm9yKCBpIGluIDE6bGVuZ3RoKGFsbERFR3NfZGF0YXNldEIpKSB7CiAgQ291bnRzX2RhdGFzZXRCW2ksMV08LSBhbGxERUdzX2RhdGFzZXRCW2ldICVpbiUgREVHc1VuYWRqX2RhdGFzZXRCCiAgQ291bnRzX2RhdGFzZXRCW2ksMl08LSBhbGxERUdzX2RhdGFzZXRCW2ldICVpbiUgREVHc1JVVjRfZGF0YXNldEJfYWxsX2tbW0tdXQp9Cgpjb2wgPC0gYygiYmx1ZSIsICJkYXJrZ3JlZW4iKQp2ZW5uRGlhZ3JhbSh2ZW5uQ291bnRzKENvdW50c19kYXRhc2V0QiksIAogICAgICAgICAgICBjaXJjbGUuY29sID0gY29sLCAKICAgICAgICAgICAgY2V4ID0gYygxLjYsIDEuMiwgMSksIGx3ZCA9IDIpCmBgYAoKCgoKCgo=